package com.yunhe.policyfulfillment.policyful.service.impl;
import com.yunhe.common.util.DateTimeUtils;
import com.yunhe.common.util.StringUtil;
import com.yunhe.policyfulfillment.authority.domain.PolicyOrg;
import com.yunhe.policyfulfillment.authority.service.IPolicyOrgService;
import com.yunhe.policyfulfillment.constant.PolicyFulfillmentConstant;
import com.yunhe.policyfulfillment.policyful.domain.PolicyApplyMatterStatistics;
import com.yunhe.policyfulfillment.policyful.domain.PolicyInfoApplyMatter;
import com.yunhe.policyfulfillment.policyful.domain.PolicyInfoApproveProcess;
import com.yunhe.policyfulfillment.policyful.model.ApprovalStatisticalAnalysis;
import com.yunhe.policyfulfillment.policyful.model.PolicyStatisticsRateVO;
import com.yunhe.policyfulfillment.policyful.repository.PolicyApplyMatterStatisticsRepository;
import com.yunhe.policyfulfillment.policyful.repository.PolicyInfoApplyMatterRepository;
import com.yunhe.policyfulfillment.policyful.repository.PolicyInfoApproveProcessRepository;
import com.yunhe.policyfulfillment.policyful.service.PolicyApplyMatterStatisticsService;
import com.yunhe.policyfulfillment.util.BigDecimalUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.yunhe.common.util.CollectionUtil;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * @description 申请事项处理统计分析
 * @author misty
 * @date 2021-09-18
 */
@Service
@Slf4j
public class PolicyApplyMatterStatisticsServiceImpl implements PolicyApplyMatterStatisticsService {

    @Autowired
    private PolicyApplyMatterStatisticsRepository policyApplyMatterStatisticsRepository;

    @Autowired
    private IPolicyOrgService policyOrgService;

    @Autowired
    private PolicyInfoApplyMatterRepository policyInfoApplyMatterRepository;

    @Autowired
    private PolicyInfoApproveProcessRepository policyInfoApproveProcessRepository;

    private static final int MAXSIZE = 200;

    private static LinkedBlockingQueue<PolicyApplyMatterStatistics> dataListBOQueue = new LinkedBlockingQueue<>();


    @Override
    public int createPolicyApplyMatterStatistics (PolicyApplyMatterStatistics policyApplyMatterStatistics) {
        return policyApplyMatterStatisticsRepository.createPolicyApplyMatterStatisticsSelective(policyApplyMatterStatistics);
    }


    @Override
    public int deletePolicyApplyMatterStatistics(int id) {
        return policyApplyMatterStatisticsRepository.deletePolicyApplyMatterStatisticsByPrimaryKey(id);
    }


    @Override
    public int updatePolicyApplyMatterStatistics(PolicyApplyMatterStatistics policyApplyMatterStatistics) {
        return policyApplyMatterStatisticsRepository.updatePolicyApplyMatterStatisticsByPrimaryKeySelective(policyApplyMatterStatistics);
    }


    @Override
    public PolicyApplyMatterStatistics findPolicyApplyMatterStatisticsById(int id) {
        return policyApplyMatterStatisticsRepository.searchPolicyApplyMatterStatisticsByPrimaryKey(id);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void  matterHandleStatistics() throws InterruptedException {
        long startTime = System.currentTimeMillis();
        //创建线程池 批量处理数据
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        executorService.submit(() -> {
            batchDataProcessing();
        });
        // 获取当前日期
        LocalDate today = LocalDate.now();
        // 获取当前日期的前一天
        String yesterday = today.plusDays(-1).toString();
        //政策兑现办
        List<PolicyOrg> policyOfficeOrgs = policyOrgService.findPolicyOrgsByOrgType(PolicyFulfillmentConstant.OrgType.PolicyOffice.value());
        if(!CollectionUtil.isEmpty(policyOfficeOrgs)){
            for (PolicyOrg policyOrg : policyOfficeOrgs) {
                assembleData(policyOrg,yesterday);
            }
        }
        //主管部门
        List<PolicyOrg> competentAuthorityOrgs = policyOrgService.findPolicyOrgsByOrgType(PolicyFulfillmentConstant.OrgType.CompetentAuthority.value());
        if(!CollectionUtil.isEmpty(competentAuthorityOrgs)){
            for (PolicyOrg policyOrg : competentAuthorityOrgs) {
                assembleData(policyOrg,yesterday);
            }
        }
        //园区
        List<PolicyOrg> parkOrgs = policyOrgService.findPolicyOrgsByOrgType(PolicyFulfillmentConstant.OrgType.Park.value());
        if(!CollectionUtil.isEmpty(parkOrgs)){
            for (PolicyOrg policyOrg : parkOrgs) {
                assembleData(policyOrg,yesterday);
            }
        }
        //财政
        List<PolicyOrg> financialOrgs = policyOrgService.findPolicyOrgsByOrgType(PolicyFulfillmentConstant.OrgType.Financial.value());
        if(!CollectionUtil.isEmpty(financialOrgs)){
            for (PolicyOrg financialOrg : financialOrgs) {
                assembleData(financialOrg,yesterday);
            }
        }
        dataListBOQueue.add(new PolicyApplyMatterStatistics());
        long endTime = System.currentTimeMillis();
        log.info("数据处理所需时间：{}",(endTime-startTime));
        log.info("数据处理结束");
        executorService.shutdown();
        executorService.awaitTermination(20, TimeUnit.SECONDS);
    }

    @Override
    public List<PolicyStatisticsRateVO> applyMatterStatistics(String time) {
        List<PolicyStatisticsRateVO> applyMatterStatistics = new ArrayList<>();
        if(StringUtil.isEmpty(time)){
            return applyMatterStatistics;
        }
        String[] split = time.split("-");
        String yearStr = split[0];
        String monthStr = split[1];
        String firstDayOfMonth = DateTimeUtils.getFirstDayOfMonth(Integer.parseInt(yearStr), Integer.parseInt(monthStr));
        String lastDayOfMonth = DateTimeUtils.getLastDayOfMonth(Integer.parseInt(yearStr), Integer.parseInt(monthStr));

        applyMatterStatistics = policyApplyMatterStatisticsRepository.getApplyMatterStatistics(firstDayOfMonth, lastDayOfMonth);
        long countSum = 0;
        if (!CollectionUtil.isEmpty(applyMatterStatistics)) {
            if(applyMatterStatistics.size()==1 && applyMatterStatistics.get(0).getOrgId()== null ){
                return new ArrayList<>();
            }
            for (PolicyStatisticsRateVO applyMatterStatistic : applyMatterStatistics) {
                countSum += applyMatterStatistic.getCount();
            }
            for (PolicyStatisticsRateVO applyMatterStatistic : applyMatterStatistics) {
                if (countSum == 0){
                    applyMatterStatistic.setRate(0.0);
                }else {
                    applyMatterStatistic.setRate(applyMatterStatistic.getCount() / (countSum*1.0));
                }
            }
        }
        return applyMatterStatistics;
    }

    @Override
    public List<PolicyStatisticsRateVO> fundReleaseStatistics(String time) {
        List<PolicyStatisticsRateVO> fundReleaseStatistics = new ArrayList<>();
        if(StringUtil.isEmpty(time)){
            return fundReleaseStatistics;
        }
        String[] split = time.split("-");
        String yearStr = split[0];
        String monthStr = split[1];
        String firstDayOfMonth = DateTimeUtils.getFirstDayOfMonth(Integer.parseInt(yearStr), Integer.parseInt(monthStr));
        String lastDayOfMonth = DateTimeUtils.getLastDayOfMonth(Integer.parseInt(yearStr), Integer.parseInt(monthStr));

        fundReleaseStatistics = policyApplyMatterStatisticsRepository.getFundReleaseStatistics(firstDayOfMonth, lastDayOfMonth);
        long countSum = 0;
        if (!CollectionUtil.isEmpty(fundReleaseStatistics)) {
            for (PolicyStatisticsRateVO fundReleaseStatistic : fundReleaseStatistics) {
                countSum += fundReleaseStatistic.getCount();
            }
            for (PolicyStatisticsRateVO fundReleaseStatistic : fundReleaseStatistics) {
                if (countSum == 0){
                    fundReleaseStatistic.setRate(0.0);
                }else {
                    fundReleaseStatistic.setRate(fundReleaseStatistic.getCount() / (countSum*1.0));
                }
            }
        }
        return fundReleaseStatistics;
    }

    @Override
    public List<ApprovalStatisticalAnalysis> approvalStatisticalAnalysis(String time, String orgType) throws ParseException {
        List<ApprovalStatisticalAnalysis> thisMonthStatistics = new ArrayList<>();
        if(StringUtil.isEmpty(time)){
            return thisMonthStatistics;
        }
        String[] split = time.split("-");
        String yearStr = split[0];
        String monthStr = split[1];
        String firstDayOfMonth = DateTimeUtils.getFirstDayOfMonth(Integer.parseInt(yearStr), Integer.parseInt(monthStr));
        String lastDayOfMonth = DateTimeUtils.getLastDayOfMonth(Integer.parseInt(yearStr), Integer.parseInt(monthStr));

        //查询各主管部门本月申请处理量
        thisMonthStatistics = policyApplyMatterStatisticsRepository.getApplyProcessCount(firstDayOfMonth, lastDayOfMonth, orgType);
        //计算申请处理量占比和平均流程处理时间
        int applyProcessSum = 0;
        for (ApprovalStatisticalAnalysis thisMonthStatistic : thisMonthStatistics) {
            applyProcessSum += thisMonthStatistic.getApplyProcessCount();
        }
        for (ApprovalStatisticalAnalysis thisMonthStatistic : thisMonthStatistics) {
            if (applyProcessSum == 0){
                thisMonthStatistic.setRate(0.0);
                thisMonthStatistic.setAverageProcessingTime(0.0);
            }else {
                double rate = thisMonthStatistic.getApplyProcessCount() / (applyProcessSum*1.0);
                BigDecimal bd = new BigDecimal(rate);
                thisMonthStatistic.setRate(bd.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());
                double averageProcessingTime = thisMonthStatistic.getProcessingTime() / (applyProcessSum*1.0);
                BigDecimal bd1 = new BigDecimal(averageProcessingTime);
                thisMonthStatistic.setAverageProcessingTime(bd1.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());
                String averageProcessingTimeStr = String.valueOf(bd1.setScale(1, BigDecimal.ROUND_HALF_UP).doubleValue());
                thisMonthStatistic.setAverageProcessingTimeStr(averageProcessingTimeStr + "小时");
            }
        }
        //查询各主管部门上月申请处理量
        String lastMonthFirstDay = getLastMonthDate(firstDayOfMonth);
        String lastMonthLastDay = getLastMonthDate(lastDayOfMonth);
        List<ApprovalStatisticalAnalysis> lastMonthStatistics = policyApplyMatterStatisticsRepository.getApplyProcessCount(lastMonthFirstDay, lastMonthLastDay, orgType);
        //计算上月平均流程处理时间
        int lastMonthApplyProcessSum = 0;
        for (ApprovalStatisticalAnalysis lastMonthStatistic : lastMonthStatistics) {
            lastMonthApplyProcessSum += lastMonthStatistic.getApplyProcessCount();
        }
        Map<Integer, Double> lastMonthAverageProcessingTimeMap = new HashMap<>();
        for (ApprovalStatisticalAnalysis lastMonthStatistic : lastMonthStatistics) {
            if (lastMonthApplyProcessSum == 0){
                lastMonthStatistic.setAverageProcessingTime(0.0);
            }else {
                lastMonthStatistic.setAverageProcessingTime(lastMonthStatistic.getProcessingTime() / (lastMonthApplyProcessSum*1.0));
            }
            lastMonthAverageProcessingTimeMap.put(lastMonthStatistic.getOrgId(), lastMonthStatistic.getAverageProcessingTime());
        }
        //计算平均流程处理时间环比变化量
        for (ApprovalStatisticalAnalysis thisMonthStatistic : thisMonthStatistics) {
            double thisMonthData = thisMonthStatistic.getAverageProcessingTime();
            double lastMonthData = 0.0;
            if (lastMonthAverageProcessingTimeMap.get(thisMonthStatistic.getOrgId()) != null){
                lastMonthData = lastMonthAverageProcessingTimeMap.get(thisMonthStatistic.getOrgId());
            }
            double ringRatio = 0.0;
            if (lastMonthData == 0.0){
                ringRatio = 1.0;
                if (thisMonthData - lastMonthData == 0){
                    ringRatio = 0.0;
                }
            }else {
                ringRatio = (thisMonthData - lastMonthData)/lastMonthData;
            }
            BigDecimal bd = new BigDecimal(ringRatio);
            thisMonthStatistic.setRingRatio(bd.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());
        }
        return thisMonthStatistics;
    }
    /**
     * @Description 根据日期获取上个月这一天的日期
     * @Param String date
     * @Return String
     * @Date 2021/9/19 15:45
     */
    public String getLastMonthDate(String currentDateStr) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date currentDate = sdf.parse(currentDateStr);
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(currentDate);
        calendar.add(Calendar.MONTH, -1);
        Date lastMonthDate = calendar.getTime();
        String lastMonthDateStr = sdf.format(lastMonthDate);
        return lastMonthDateStr;
    }

    /**
     * 组装数据
     */
    private void assembleData(PolicyOrg policyOrg,String yesterday){
        PolicyApplyMatterStatistics policyApplyMatterStatistics = new PolicyApplyMatterStatistics();
        policyApplyMatterStatistics.setOrgId(policyOrg.getId());
        policyApplyMatterStatistics.setOrgType(policyOrg.getOrgType());
        policyApplyMatterStatistics.setDataTime(DateTimeUtils.formatToDate(yesterday,DateTimeUtils.PATTERN.DATE.value()));
        List<PolicyInfoApproveProcess> policyInfoApproveProcessList = policyInfoApproveProcessRepository.searchPolicyInfoApproveProcessByOrgId(policyOrg.getId());
        if(!CollectionUtil.isEmpty(policyInfoApproveProcessList)){
            //统计处理事项条数
            Map<Long, List<PolicyInfoApproveProcess>> map = policyInfoApproveProcessList.stream().collect(Collectors.groupingBy(PolicyInfoApproveProcess::getApplyMatterId));
            if(!CollectionUtil.isEmpty(map)){
                policyApplyMatterStatistics.setApplyMatterCount((long) map.keySet().size());
                AtomicReference<Long> processingTimeLong = new AtomicReference<>(0L);
                for (Long key : map.keySet()) {
                    PolicyInfoApplyMatter policyInfoApplyMatter = policyInfoApplyMatterRepository.searchPolicyInfoApplyMatterByPrimaryKey(Math.toIntExact(key));
                    List<PolicyInfoApproveProcess> approveProcesses = map.get(key);
                    if(!CollectionUtil.isEmpty(approveProcesses)){
                        approveProcesses.forEach(policyInfoApproveProcess -> {
                            processingTimeLong.updateAndGet(v -> v + policyInfoApproveProcess.getApproveTime().getTime() - policyInfoApplyMatter.getApplyTime().getTime());
                        });
                    }
                }
                Long value = processingTimeLong.get();
                double calculationValue = 0.0;
                PolicyFulfillmentConstant.OrgType orgType = PolicyFulfillmentConstant.OrgType.byValue(policyApplyMatterStatistics.getOrgType());
                switch (orgType){
                    case Park:
                        calculationValue = value==null?0.0:value/2.0;
                        break;
                    case PolicyOffice:
                        calculationValue = value==null?0.0:value/1.0;
                        break;
                    case CompetentAuthority:
                        calculationValue = value==null?0.0:value/2.0;
                        break;
                }
                policyApplyMatterStatistics.setProcessingTime(BigDecimalUtil.div(BigDecimal.valueOf(calculationValue),BigDecimal.valueOf(1000*60*60),2));
            }
        }
        dataListBOQueue.add(policyApplyMatterStatistics);
    }

    private void batchDataProcessing() {
        try {
            for (; ; ) {
                List<PolicyApplyMatterStatistics> dataLists = new ArrayList<>(100);
                for (int i = 0; i < MAXSIZE; i++) {
                    PolicyApplyMatterStatistics take = dataListBOQueue.take();
                    if (take == null || take.getOrgId() ==null) {
                        if (!CollectionUtil.isEmpty(dataLists)) {
                            policyApplyMatterStatisticsRepository.batchCreatePolicyApplyMatterStatistics(dataLists);
                        }
                        return;
                    } else {
                        dataLists.add(take);
                    }
                }
                if (!CollectionUtil.isEmpty(dataLists)) {
                    policyApplyMatterStatisticsRepository.batchCreatePolicyApplyMatterStatistics(dataLists);
                    dataLists.clear();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }



}